ConfigMap 是 Kubernetes 中的一種資源,用來將非機密的設定資料(如設定檔案、環境變數)與容器分離。這使得應用程式可以在不同的環境中更靈活地使用相同的映像檔,而不需要將設定硬編碼到映像檔中。
ConfigMap 的主要目的是讓應用程式設定和容器鏡像解耦。這樣做的好處是:
在 Pod 中使用 ConfigMap,通常有兩種做法: 掛載為文件
、設為環境變量
。這兩種做法有不同的更新策略:
環境變量
,需要重啟 Pod掛載為文件
的情況,Kubernetes 會自動更新(可能有延遲)一個簡單的 ConfigMap 組態檔案如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config
data:
# 簡單的 key-value 配對
app.properties: |
key1=value1
key2=value2
# 或者可以單獨列出多個鍵
database_url: "jdbc:mysql://dbhost:3306/mydb"
database_user: "admin"
database_password: "password"
apiVersion: v1
:指定使用的 Kubernetes API 版本為 v1。kind: ConfigMap
:指定這個資源的類型是 ConfigMap。metadata
:
name: my-config
:ConfigMap 的名稱是 my-config
。data
:ConfigMap 包含的數據。
app.properties
:一個多行屬性文件,用來存儲簡單的 key-value 配對。
key1=value1
key2=value2
database_url
:指定數據庫的連接 URL。database_user
:指定數據庫的用戶名。database_password
:指定數據庫的密碼。在這個範例中,my-config
是 ConfigMap 的名稱。data
區塊包含了應用程式所需的配置資料。這些資料可以在 Pod 中以環境變數、命令列引數或檔案的形式使用。
透過 ConfigMap,Kubernetes 提供了一個靈活的機制來管理和分發應用程式的設定資料,使得應用程式能夠更容易適應不同的運行環境。
組態檔案: cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
data:
debug: "false"
log_level: INFO
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
user: vincent
password: vincent_12345678
init.sql: |
-- create
CREATE TABLE USER (
id INT PRIMARY KEY,
user_id varchar(100),
login_date DATE
);
-- insert
INSERT INTO USER VALUES (1, 'a1', '1970-01-01 00:00:00');
INSERT INTO USER VALUES (2, 'a2', '2024-04-07 00:00:00');
INSERT INTO USER VALUES (3, 'a3', '1990-01-01 00:00:00');
這個組態檔定義了兩個 Kubernetes ConfigMap
資源。
env-config
這個 ConfigMap
主要用於存儲應用程式的環境配置,通常用於在容器內通過環境變數或掛載檔案的形式注入到應用程式中。
mysql-config
這個 ConfigMap
可能會用於初始化 MySQL 資料庫,例如在容器啟動時運行該 SQL 腳本來設定資料庫結構和初始數據。
建立 ConfigMap
kubectl create -f cm.yaml
組態檔案: pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
- name: MYSQL_USER
valueFrom:
configMapKeyRef:
name: mysql-config
key: user
restartPolicy: Never
spec.containers.env
:定義環境變量。
LOG_LEVEL
:從 env-config
ConfigMap 中提取 log_level
鍵的值,並將其設置為環境變量 LOG_LEVEL
。MYSQL_USER
:從 mysql-config
ConfigMap 中提取 user
鍵的值,並將其設置為環境變量 MYSQL_USER
。部署 Pod
kubectl apply -f pod.yaml
kubectl logs dapi-test-pod
---
[...]
LOG_LEVEL=INFO
[...]
MYSQL_USER=vincent
[...]
可以看到 env 裡包含我們引用的環境變數
kubectl delete -f pod.yaml --now
在 pod 指令參數 (
command
,args
) 中,可以使用$(VAR_NAME)
引用 ConfigMap 定義的環境變數。
組態檔案: pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/echo", "$(LOG_LEVEL) $(MYSQL_USER)" ]
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
- name: MYSQL_USER
valueFrom:
configMapKeyRef:
name: mysql-config
key: user
restartPolicy: Never
command: [ "/bin/echo", "$(LOG_LEVEL) $(MYSQL_USER)" ]
:此命令將輸出環境變量 LOG_LEVEL
和 MYSQL_USER
的值。這些值是從指定的 ConfigMap 中提取的。
kubectl apply -f pod.yaml
kubectl logs dapi-test-pod
---
INFO vincent
可以看到 command 可以正確參考環境變數
kubectl delete -f pod.yaml --now
在引用 Volume 時,K8s 也提供 ConfigMap 來源,當我們使用 ConfigMap 當作 Volume 來源時,K8S 會在我們指定的目錄中產生對應的檔案: ConfigMap 的 Key 為檔名,ConfigMap 的 Value 為檔案的內容。
組態檔案: pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "ls /mnt/data; while true; do echo ''; sleep 3600; done" ]
volumeMounts:
- name: config-volume
mountPath: /mnt/data
volumes:
- name: config-volume
configMap:
# 提供包含要新增到容器中的檔案的 ConfigMap 的名稱
name: mysql-config
restartPolicy: Never
containers[].volumeMounts
:
name: config-volume
:這個卷是從 ConfigMap mysql-config
中獲取的,並掛載到容器內的 /mnt/data
目錄。mysql-config
ConfigMap 中的所有鍵值對將會作為文件映射到 /mnt/data
目錄。每個鍵將變成一個文件名,對應的值將成為文件內容。volumes
:
configMap
:指定使用 ConfigMap mysql-config
來創建一個卷。該 ConfigMap 的內容會以文件的形式存儲在卷中,並掛載到容器的指定目錄。補充:
執行完ls /mnt/data
指令後,實際上是列出文件后立即退出,會導致容器完成任務而退出,變成 Complete。為了避免 pod 立即結束,在 command 後面加上while true; do echo ''; sleep 3600; done"
無窮迴圈是一個解決方法。
kubectl apply -f pod.yaml
kubectl logs dapi-test-pod
---
init.sql
password
user
可以看到 /mnt/data
路徑有我們在 mysql-config
定義,以鍵值為名的檔案
kubectl exec
指令查詢該檔案kubectl exec dapi-test-pod -- sh -c 'cat /mnt/data/password'
---
vincent_12345678
kubectl exec dapi-test-pod -- sh -c 'cat /mnt/data/init.sql'
---
-- create
CREATE TABLE USER (
id INT PRIMARY KEY,
user_id varchar(100),
login_date DATE
);
-- insert
INSERT INTO USER VALUES (1, 'a1', '1970-01-01 00:00:00');
INSERT INTO USER VALUES (2, 'a2', '2024-04-07 00:00:00');
INSERT INTO USER VALUES (3, 'a3', '1990-01-01 00:00:00');
可以看到 value 就在裡面
kubectl delete -f pod.yaml --now
組態檔案: pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh","-c","ls /mnt/data; while true; do echo ''; sleep 3600; done" ]
volumeMounts:
- name: config-volume
mountPath: /mnt/data
volumes:
- name: config-volume
configMap:
name: mysql-config
items:
- key: user
path: mysql_user
restartPolicy: Never
volumes.configMap
:
name: mysql-config
:指定 ConfigMap 的名稱為 mysql-config
。items
:
key: user
:表示只從 mysql-config
中取出 user
鍵。path: mysql_user
:將 user
鍵的內容存儲到 /mnt/data/mysql_user
文件中。這樣,容器內的 /mnt/data/mysql_user
將包含 user
鍵的值,即 vincent
。kubectl apply -f pod.yaml
kubectl logs dapi-test-pod
---
mysql_user
可以看到 /mnt/data
路徑有重新命名後的物件名稱
kubectl exec dapi-test-pod -- sh -c 'cat /mnt/data/mysql_user'
---
vincent
內容對應的的確是 mysql-config
/user
kubectl delete -f pod.yaml --now
從上面的練習可知,Pod 可以透過設定環境變數、掛載 Volume 兩種方式引用 ConfigMap 內容。
當已掛載的 ConfigMap 被更新時,所投射的內容最終也會被更新。不過這僅限於使用 Volume 掛載的方式,若是透過環境變數的 Pod ,只有等到 Pod 重啟時才會更新投射的 ConfigMap 內容。
不過掛載 Volume 也不是馬上就會更新,而是 kubelet 同步週期(默認為 1 分鐘)+ kubelet 中 ConfigMap 快取的 TTL(默認為 1 分鐘),也可以透過更新 Pod 立即刷新。
我們可以來實踐一下:
組態檔案: pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "sleep 3600" ]
volumeMounts:
- name: config-volume
mountPath: /mnt/data
volumes:
- name: config-volume
configMap:
name: env-config
items:
- key: log_level
path: log_level
restartPolicy: Never
---
apiVersion: v1
kind: Pod
metadata:
name: env-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "sleep 3600" ]
env:
- name: log_level
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
restartPolicy: Never
log_level
kubectl exec volume-pod -- sh -c 'cat /mnt/data/log_level'
---
INFO
kubectl exec env-pod -- sh -c 'echo "$log_level"'
---
INFO
kubectl pathc
指令修改 log_level 的內容kubectl patch configmap env-config -p '{"data":{"log_level":"ERROR"}}'
log_level
kubectl exec volume-pod -- sh -c 'cat /mnt/data/log_level'
---
ERROR
kubectl env-pod -- sh -c 'echo "$log_level"'evel'
---
INFO
ConfigMap 提供了一個靈活且高效的方式來管理和分發應用程式的設定資料,使 Kubernetes 中的應用部署更加模組化和可維護。通過本文的實例操作,各位可以掌握 ConfigMap 的基本使用方法及其在實際場景中的應用技巧。